package dnaSequencer;

import java.io.FileNotFoundException;
import java.util.ArrayList;

public class HeurystykaPozytywne {
    boolean debug;
    boolean log;
    boolean random;

    private String fileName = null;
    private ArrayList<String> oligonukleotydy = null;
    private int singlePieceLength;
    private int totalLength;

    private ArrayList<DNAPiece> DNApieces = null;
    private int usedWords;

    public HeurystykaPozytywne(String fileName, String params) {
        this.fileName = fileName;
        if (params != null) {
            if (params.contains("r"))
                random = true;
            else
                random = false;

            if (params.contains("l"))
                log = true;
            else
                log = false;

            if (params.contains("d"))
                debug = true;
            else
                debug = false;

        } else {
            log = false;
            debug = false;
            random = false;
        }
    }

    public void run() {
        long start, stop;
        load();
        start = System.currentTimeMillis();
        buildDNA();
        pruneDNA();
        stop = System.currentTimeMillis();

        System.out.println("Czas " + (stop - start) + " ms");
    }

    private void load() {
        try {
            oligonukleotydy = ResultsParser.loadResultsFromFile(fileName);
            singlePieceLength = ResultsParser.getL();
            totalLength = ResultsParser.getN();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    private int removeAlienatedNodes(ArrayList<Integer>[] listaNastepnikow,
            ArrayList<Integer>[] listaPoprzednikow) {
        int count = 0;

        int i = 0;
        int j = 0;
        while (i < oligonukleotydy.size()) {
            if (listaNastepnikow[i] == null && listaPoprzednikow[i] == null) {
                count++;
                oligonukleotydy.remove(j);
            } else
                j++;
            i++;
        }

        //System.out.println("Usuniete: " + count + " i jest " + oligonukleotydy.size());

        return count;
    }

    private void buildDNA() {

        ArrayList<Integer>[] listaNastepnikow = AlgorytmyGrafowe
                .utworzListeNastepnikow(oligonukleotydy);
        ArrayList<Integer>[] listaPoprzednikow = AlgorytmyGrafowe
                .utworzListePoprzednikow(oligonukleotydy);

        if (removeAlienatedNodes(listaNastepnikow, listaPoprzednikow) > 0) {
            listaNastepnikow = AlgorytmyGrafowe
                    .utworzListeNastepnikow(oligonukleotydy);
            listaPoprzednikow = AlgorytmyGrafowe
                    .utworzListePoprzednikow(oligonukleotydy);
        }

        int[] silnieSpojneSkladowe = AlgorytmyGrafowe
                .znajdzSilnieSpojneSkladowe(listaPoprzednikow, listaNastepnikow);

        if (log) {
            for (int i = 0; i < silnieSpojneSkladowe.length; i++) {
                System.out.println(oligonukleotydy.get(i) + " "
                        + silnieSpojneSkladowe[i]);
            }
        }
        
        int ile = 0;
        
        while (AlgorytmyGrafowe.usunCykle(listaPoprzednikow, listaNastepnikow,
                silnieSpojneSkladowe)) {
            if (log)
                System.out.println("USUNIETO CYKLE");
            ile++;
            silnieSpojneSkladowe = AlgorytmyGrafowe.znajdzSilnieSpojneSkladowe(
                    listaPoprzednikow, listaNastepnikow);

            if (log) {
                for (int i = 0; i < silnieSpojneSkladowe.length; i++) {
                    System.out.println(oligonukleotydy.get(i) + " "
                            + silnieSpojneSkladowe[i]);
                }
            }
        }
        
        //System.out.println("Cykle: " + ile);

      /*  if (log)
            System.out.println("SORTUJE TOPOLOGICZNIE");

        int[] sort = AlgorytmyGrafowe.topSort(listaPoprzednikow,
                listaNastepnikow);

        if (log) {
            for (int i = 0; i < sort.length; i++) {
                System.out
                        .println(oligonukleotydy.get(i) + " " + (sort[i] + 1));
            }
        }*/

        if (log)
            System.out.println("WYZNACZAM GLEBOKOSC");


        /*int depth[] = AlgorytmyGrafowe.dfs(listaNastepnikow,
         silnieSpojneSkladowe);*/



        int bezPoprzednikow[] = AlgorytmyGrafowe.wierzcholkiBezPoprz(listaPoprzednikow);
        
        int depth[] = AlgorytmyGrafowe.dfsSpecial(listaNastepnikow,bezPoprzednikow, totalLength - singlePieceLength + 1);

        if (log) {
            for (int i = 0; i < depth.length; i++) {
                System.out.println(oligonukleotydy.get(i) + " " + depth[i]);
            }
        }

        int maxDepth = -1;
        int curr = -1;
        for (int i = 0; i < depth.length; i++) {
            if (depth[i] > maxDepth) {
                maxDepth = depth[i];
                curr = i;
            }
        }

         if (log)
        System.out.println("MAX DEPTH = " + maxDepth);

        DNAPiece tmpDNA = new DNAPiece(singlePieceLength);

        tmpDNA.add(oligonukleotydy.get(curr), DNAPiece.FRONT);
        while (listaPoprzednikow[curr] != null) {
            if (!(listaPoprzednikow[curr].size() > 0)) {
                break;
            }
            for (int i : listaPoprzednikow[curr]) {
                if (depth[i] + 1 == depth[curr]) {
                    tmpDNA.add(oligonukleotydy.get(i), DNAPiece.FRONT);
                    curr = i;
                }
            }
        }

        if (log)
            System.out.println("DNA\t" + tmpDNA.getDNA());

        DNApieces = new ArrayList<DNAPiece>();
        DNApieces.add(tmpDNA);

        int actualLength = 0;
        DNAPiece DNA = null;

        DNA = DNApieces.get(0);

        actualLength = DNA.getDNALength();
        while (actualLength > totalLength) {
            if (DNA.getZakladkaLength(DNAPiece.BACK) < DNA
                    .getZakladkaLength(DNAPiece.FRONT))
                DNA.removeOne(DNAPiece.BACK);
            else
                DNA.removeOne(DNAPiece.FRONT);
            actualLength = DNA.getDNALength();
        }

        System.out.println("Użyłem słów: " + DNA.getUseWordsCount() + "/"
                    + (totalLength - 9));

        System.out.println(fileName + ": Sumaryczna dlugosc to: "
                + actualLength + "/" + totalLength);
        
    }

    private void pruneDNA() {
        /* TODO tu bedzie trzeba jeszcze pomyslec czy cos trzeba robic */

        /*
         * int actualLength = 0; DNAPiece DNA = null;
         * 
         * DNA = DNApieces.get(0); actualLength = DNA.getDNALength(); while
         * (actualLength > totalLength) { if
         * (DNA.getZakladkaLength(DNAPiece.BACK) < DNA
         * .getZakladkaLength(DNAPiece.FRONT)) DNA.removeOne(DNAPiece.BACK);
         * else DNA.removeOne(DNAPiece.FRONT); actualLength =
         * DNA.getDNALength(); } if (log) System.out.println("Skonczylem z DNA "
         * + DNA.getDNA());
         * 
         * System.out.println("Użyłem słów: " + DNA.getUseWordsCount() + "/"
         * + oligonukleotydy.size());
         * 
         * System.out.println(fileName + ": Sumaryczna długość to: " +
         * actualLength + "/" + totalLength);
         */
    }
}
